// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_HTTP_HTTP_AUTH_H_
#define NET_HTTP_HTTP_AUTH_H_

#include <memory>
#include <set>
#include <string>

#include "net/base/auth.h"
#include "net/base/net_export.h"
#include "net/http/http_util.h"

template <class T>
class scoped_refptr;

namespace net {

class BoundNetLog;
class HttpAuthHandler;
class HttpAuthHandlerFactory;
class HttpResponseHeaders;
class SSLInfo;

// Utility class for http authentication.
class NET_EXPORT_PRIVATE HttpAuth {
public:
    // Http authentication can be done the the proxy server, origin server,
    // or both. This enum tracks who the target is.
    enum Target {
        AUTH_NONE = -1,
        // We depend on the valid targets (!= AUTH_NONE) being usable as indexes
        // in an array, so start from 0.
        AUTH_PROXY = 0,
        AUTH_SERVER = 1,
        AUTH_NUM_TARGETS = 2,
    };

    // What the HTTP WWW-Authenticate/Proxy-Authenticate headers indicate about
    // the previous authorization attempt.
    enum AuthorizationResult {
        AUTHORIZATION_RESULT_ACCEPT, // The authorization attempt was accepted,
        // although there still may be additional
        // rounds of challenges.

        AUTHORIZATION_RESULT_REJECT, // The authorization attempt was rejected.

        AUTHORIZATION_RESULT_STALE, // (Digest) The nonce used in the
        // authorization attempt is stale, but
        // otherwise the attempt was valid.

        AUTHORIZATION_RESULT_INVALID, // The authentication challenge headers are
        // poorly formed (the authorization attempt
        // itself may have been fine).

        AUTHORIZATION_RESULT_DIFFERENT_REALM, // The authorization
        // attempt was rejected,
        // but the realm associated
        // with the new challenge
        // is different from the
        // previous attempt.
    };

    // Describes where the identity used for authentication came from.
    enum IdentitySource {
        // Came from nowhere -- the identity is not initialized.
        IDENT_SRC_NONE,

        // The identity came from the auth cache, by doing a path-based
        // lookup (premptive authorization).
        IDENT_SRC_PATH_LOOKUP,

        // The identity was extracted from a URL of the form:
        // http://<username>:<password>@host:port
        IDENT_SRC_URL,

        // The identity was retrieved from the auth cache, by doing a
        // realm lookup.
        IDENT_SRC_REALM_LOOKUP,

        // The identity was provided by RestartWithAuth -- it likely
        // came from a prompt (or maybe the password manager).
        IDENT_SRC_EXTERNAL,

        // The identity used the default credentials for the computer,
        // on schemes that support single sign-on.
        IDENT_SRC_DEFAULT_CREDENTIALS,
    };

    enum Scheme {
        AUTH_SCHEME_BASIC = 0,
        AUTH_SCHEME_DIGEST,
        AUTH_SCHEME_NTLM,
        AUTH_SCHEME_NEGOTIATE,
        AUTH_SCHEME_SPDYPROXY,
        AUTH_SCHEME_MOCK,
        AUTH_SCHEME_MAX,
    };

    // Helper structure used by HttpNetworkTransaction to track
    // the current identity being used for authorization.
    struct Identity {
        Identity();

        IdentitySource source;
        bool invalid;
        AuthCredentials credentials;
    };

    // Get the name of the header containing the auth challenge
    // (either WWW-Authenticate or Proxy-Authenticate).
    static std::string GetChallengeHeaderName(Target target);

    // Get the name of the header where the credentials go
    // (either Authorization or Proxy-Authorization).
    static std::string GetAuthorizationHeaderName(Target target);

    // Returns a string representation of a Target value that can be used in log
    // messages.
    static std::string GetAuthTargetString(Target target);

    // Returns a string representation of an authentication Scheme.
    static const char* SchemeToString(Scheme scheme);

    // Iterate through |response_headers|, and pick the best one that we support.
    // Obtains the implementation class for handling the challenge, and passes it
    // back in |*handler|. If no supported challenge was found, |*handler| is set
    // to NULL.
    //
    // |disabled_schemes| is the set of schemes that we should not use.
    //
    // |origin| is used by the NTLM and Negotiation authentication scheme to
    // construct the service principal name. It is ignored by other schemes.
    //
    // |ssl_info| is passed through to the scheme specific authentication handlers
    // to use as appropriate.
    static void ChooseBestChallenge(
        HttpAuthHandlerFactory* http_auth_handler_factory,
        const HttpResponseHeaders& response_headers,
        const SSLInfo& ssl_info,
        Target target,
        const GURL& origin,
        const std::set<Scheme>& disabled_schemes,
        const BoundNetLog& net_log,
        std::unique_ptr<HttpAuthHandler>* handler);

    // Handle a 401/407 response from a server/proxy after a previous
    // authentication attempt. For connection-based authentication schemes, the
    // new response may be another round in a multi-round authentication sequence.
    // For request-based schemes, a 401/407 response is typically treated like a
    // rejection of the previous challenge, except in the Digest case when a
    // "stale" attribute is present.
    //
    // |handler| must be non-NULL, and is the HttpAuthHandler from the previous
    // authentication round.
    //
    // |response_headers| must contain the new HTTP response.
    //
    // |target| specifies whether the authentication challenge response came
    // from a server or a proxy.
    //
    // |disabled_schemes| are the authentication schemes to ignore.
    //
    // |challenge_used| is the text of the authentication challenge used in
    // support of the returned AuthorizationResult. If no headers were used for
    // the result (for example, all headers have unknown authentication schemes),
    // the value is cleared.
    static AuthorizationResult HandleChallengeResponse(
        HttpAuthHandler* handler,
        const HttpResponseHeaders& response_headers,
        Target target,
        const std::set<Scheme>& disabled_schemes,
        std::string* challenge_used);
};

} // namespace net

#endif // NET_HTTP_HTTP_AUTH_H_
